﻿using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;


namespace TextGenerator
{
    /// <summary>
    /// Encapsules query performance measuring in the form of a timer.
    /// </summary>
    public class Timer
    {
        #region Timer Fields.

        /// <summary>
        /// The frequency (in number of ticks per second).
        /// </summary>
        private readonly long frequency;

        /// <summary>
        /// The time (in ticks) when the timer was started.
        /// </summary>
        private long startTime;

        /// <summary>
        /// The time (in ticks) when the timer was stopped.
        /// </summary>
        private long endTime;

        #endregion Timer Fields.

        #region Platform Invoke.

        /// <summary>
        /// Gets the current performance count.
        /// </summary>
        /// <param name="lpPerformanceCount">The current performance count.</param>
        /// <returns>
        /// True if the operation was successfull, 
        /// False otherwise.
        /// </returns>
        [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
            Justification = "Reviewed. Suppression is OK here.")]
        [DllImport("kernel32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

        /// <summary>
        /// Returns the number of counts per second for the high-performance counter.
        /// </summary>
        /// <param name="frequency">The frequency.</param>
        /// <returns>
        /// True if the operation was successfull, 
        /// False otherwise.
        /// </returns>
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool QueryPerformanceFrequency(out long frequency);

        #endregion Platform Invoke.

        /// <summary>
        /// Initializes a new instance of the <see cref="Timer"/> class.
        /// </summary>
        public Timer()
        {
            // Get the number of counts per second.
            this._canMeasureTime = QueryPerformanceFrequency(out this.frequency);
        }

        #region Properties.
        private readonly bool _canMeasureTime;

        /// <summary>
        /// Gets a value indicating whether the timer is able to measure the time.
        /// </summary>
        public bool CanMeasureTime
        {
            get { return this._canMeasureTime; }
        }

        private bool _isRunning = false;
        /// <summary>
        /// Gets a value indicating whether a timing is in progress.
        /// </summary>
        public bool IsRunning
        {
            get { return this._isRunning; }

            private set { this._isRunning = value; }
        }

        /// <summary>
        /// Gets the elapsed time between when <see cref="Start"/> and 
        /// <see cref="Stop"/> was called (in that order).
        /// </summary>
        public double Duration
        {
            get
            {
                if (!CanMeasureTime)
                    return 0d;

                long duration = this.endTime - this.startTime;
                if (this.frequency == 0d || duration == 0d)
                    return 0d;

                return duration / (double)this.frequency;
            }
        }
        #endregion Properties.

        #region Timer Operational Methods.
        /// <summary>
        /// Starts the performance counter by recording the start time.
        /// </summary>
        public void Start()
        {
            if (!IsRunning && CanMeasureTime)
            {
                IsRunning = true;
                QueryPerformanceCounter(out this.startTime);
            }
        }

        /// <summary>
        /// Stops the performance counter by recording the end time.
        /// </summary>
        public void Stop()
        {
            if (IsRunning && CanMeasureTime)
            {
                QueryPerformanceCounter(out this.endTime);
                IsRunning = false;
            }
        }
        #endregion Timer Operational Methods.
    }
}